//###############
//FILE : MyFileManager.java
//WRITER : Daniel Lowengrub, daniel_i_l, 320687098
//EXERCISE : oop ex3 2011
//DESCRIPTION:
//See below
//###############
package oop.ex3.filemanager;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import oop.ex3.communication.Communication;
import oop.ex3.communication.Request;
import oop.ex3.communication.RequestThreadDispatcher;
import oop.ex3.communication.SocketAddress;

/**
 * This implements the file manager a specified in the assignment. It opens two
 * threads. One is used for getting user input and the other is used for handling
 * requests from other FMs.
 * It also stores a database of files and a DB of nameservers. It waits for all requests
 * to be handled before exiting.
 * 
 * The command line arguments should be of the form:
 * database_directory, nameserver_file, port_number
 * @author daniel
 */
public class MyFileManager {
    private static final int NAME_DATA_ARG = 0;
    private static final int DIRECTORY_ARG = 1;
    private static final int PORT_ARG = 2;
    
    private static final String INIT_ERROR = "Couldn't initialize manager";

    private static UserThread _userThread;
    private static FileDatabase _fileDatabase;
    private static NameServerDatabase _nameServerDatabase;
    private static NameServerConnection _nameServerConnection;
    private static SocketAddress _address;
    private static RequestThreadDispatcher _requestDispatcher;

    /**
     * Initialize and run the request dispatcher (that handles requests) and the
     * user command thread.
     * @param args command line arguments (see above).
     */
    public static void main(String[] args){
        try {
            initializeManager(args);
        } catch (Exception e) {
            //e.printStackTrace();
        	System.err.println(INIT_ERROR);
            return;
        }
            _requestDispatcher.start();
            _userThread.start();
            
        try {
            _userThread.join();
            _requestDispatcher.join();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
            return;
        }
    }

    //set up the file and NS databases and initialize the two threads.
    private static void initializeManager(String[] args) throws FileNotFoundException, IOException {
        _fileDatabase = new SimpleFileDatabase(args[DIRECTORY_ARG]);
        _nameServerDatabase = new NameServerDatabase(args[NAME_DATA_ARG]);

        String ip = Communication.getLocalIp();
        int port = Integer.parseInt(args[PORT_ARG]);
        _address = new SocketAddress(ip, port);

        _nameServerConnection = new NameServerConnection(_fileDatabase, _nameServerDatabase, _address);

        //update the state of all the nameservers on the list
        FileManagerInitializer initializer = new FileManagerInitializer(_nameServerConnection);
        initializer.initFileManager();


        initializeRequestThread();
        initializeUserThread();
    }

    //add all the commands that we want to handle to the user thread.
    private static void initializeUserThread(){
        _userThread  = new UserThread();

        _userThread.addCommand(new DirCommand(_fileDatabase));
        _userThread.addCommand(new RemoveCommand(_nameServerConnection));
        _userThread.addCommand(new DirServersCommand(_nameServerDatabase));
        _userThread.addCommand(new DirAllFilesCommand(_nameServerConnection));
        _userThread.addCommand(new RenameCommand(_nameServerConnection));
        _userThread.addCommand(new FireServersCommand(_nameServerConnection));
        _userThread.addCommand(new AddCommand(_nameServerConnection));
        _userThread.addCommand(new QuitCommand(_nameServerConnection, _requestDispatcher.getServerStatus()));
    }

    //add the list of requests we want to handle to the request handler thread.
    private static void initializeRequestThread() {
        ArrayList<Request> requestList = new ArrayList<Request>();
        requestList.add(new WantFileRequest(_fileDatabase));
        FileManagerRequestThread requestThread = new FileManagerRequestThread(requestList);

        _requestDispatcher = new RequestThreadDispatcher(_address, requestThread);

    }

}
